#include "ds18b20.h"
#include "sys.h"
#include <stdint.h>

const static ds18b20_config_t *handle = NULL;

static GPIO_InitTypeDef GPIO_InitStruct;

inline void PinMode_Output(GPIO_TypeDef *port, uint16_t pin)
{
    // 修正引脚号计算
    uint8_t number = 31 - __CLZ(pin);

    port->BSRR = pin; // 建议用 = 而不是 |=

    if (number < 8)
    {
        port->CRL &= ~(0xF << (number * 4));
        port->CRL |= (0x3 << (number * 4)); // 0x3: 50MHz 推挽输出
    }
    else
    {
        port->CRH &= ~(0xF << ((number - 8) * 4));
        port->CRH |= (0x3 << ((number - 8) * 4));
    }
}

inline void PinMode_Input(GPIO_TypeDef *port, uint16_t pin)
{
    // 修正引脚号计算
    uint8_t number = 31 - __CLZ(pin);

    port->BSRR = pin; // 建议用 = 而不是 |=

    if (number < 8)
    {
        port->CRL &= ~(0xF << (number * 4));
        port->CRL |= (0x8 << (number * 4)); // 0x8: 上拉输入
    }
    else
    {
        port->CRH &= ~(0xF << ((number - 8) * 4));
        port->CRH |= (0x8 << ((number - 8) * 4));
    }
}

void DS18B20_Mode_Input(uint8_t object)
{
#if DIRECT_OPERATION_REGISTER
    PinMode_Input(handle[object].port, handle[object].pin);
#else
    GPIO_InitStruct.Pin = handle[object].pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(handle[object].port, &GPIO_InitStruct);
#endif
}

void DS18B20_Mode_Output(uint8_t object)
{
#if DIRECT_OPERATION_REGISTER
    PinMode_Output(handle[object].port, handle[object].pin);
#else
    GPIO_InitStruct.Pin = handle[object].pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(handle[object].port, &GPIO_InitStruct);
#endif
}

uint8_t DS18B20_ResetCheck(uint8_t object)
{
    uint16_t count;

    // 输出模式
    DS18B20_Mode_Output(object);

    HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_RESET);
    HAL_Delay_us(500);
    HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_SET);
    HAL_Delay_us(60);

    // 输入模式
    DS18B20_Mode_Input(object);

    while (HAL_GPIO_ReadPin(handle[object].port, handle[object].pin))
    {
        count++;
        if (count > 7200)
            return 0;
    }
    count = 0;
    while (!HAL_GPIO_ReadPin(handle[object].port, handle[object].pin))
    {
        count++;
        if (count > 7200)
            return 0;
    }
    return 1;
}

void DS18B20_Init(const ds18b20_config_t *config)
{
    handle = config;
    for (uint8_t i = 0; i < kModuleNum; i++)
    {
        GPIO_InitStruct.Pin = handle[i].pin;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(handle[i].port, &GPIO_InitStruct);
    }
}

// 发送一个字节的数据
void DS18B20_WriteByte(uint8_t object, uint8_t data)
{
    if (object >= kModuleNum)
        return;

    // 切换输出模式
    DS18B20_Mode_Output(object);
    for (uint8_t i = 0; i < 8; i++)
    {
        HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_RESET);
        HAL_Delay_us(2);
        if (data & 0x01)
        {
            HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_SET);
        }
        HAL_Delay_us(30);
        HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_SET);
        HAL_Delay_us(2);
        data >>= 1;
    }
}

// 读取一个字节的数据
uint8_t DS18B20_ReadByte(uint8_t object)
{
    uint8_t data = 0;

    if (object >= kModuleNum)
        return 0;

    for (uint8_t i = 0; i < 8; i++)
    {
        // 输出模式
        DS18B20_Mode_Output(object);
        HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_RESET);
        HAL_Delay_us(2);
        HAL_GPIO_WritePin(handle[object].port, handle[object].pin, GPIO_PIN_SET);
        // 输入模式
        DS18B20_Mode_Input(object);
        HAL_Delay_us(8);
        data >>= 1;
        if (HAL_GPIO_ReadPin(handle[object].port, handle[object].pin))
        {
            data |= 0x80;
        }
        HAL_Delay_us(60);
    }
    return data;
}

#ifdef CARRIED_OUT_SIMULTANEOUSLY

void DS18B20_GetStart(void)
{
    for (uint8_t i = 0; i < kModuleNum; i++)
    {
        if (!DS18B20_ResetCheck(i))
            continue;
        DS18B20_WriteByte(i, 0xCC); // 跳过ROM操作
        DS18B20_WriteByte(i, 0x44); // 启动温度转换
    }
}

void DS18B20_GetTempe(void)
{
    for (uint8_t i = 0; i < kModuleNum; i++)
    {
        uint16_t data = 0;
        if (!DS18B20_ResetCheck(i))
            continue;
        DS18B20_WriteByte(i, 0xCC); // 跳过ROM操作
        DS18B20_WriteByte(i, 0xBE); // 读取温度寄存器
        data = DS18B20_ReadByte(i);
        data |= ((uint16_t)DS18B20_ReadByte(i) << 8);
        *handle[i].val_ptr = (float)data * 0.0625f;
    }
}

void DS18B20_Run(void)
{
    static uint8_t start = 0;
    static uint32_t last_time = 0;

    if (start == 0)
    {
        start = 1;
        last_time = HAL_GetTick();
        DS18B20_GetStart();
    }
    else
    {
        if (HAL_GetTick() - last_time >= 500)
        {
            start = 0;
            DS18B20_GetTempe();
        }
    }
}

// void DS18B20_ReadTempe(void)
// {
//     for (uint8_t i = 0; i < (sizeof(handle) / sizeof(handle[0])); i++)
//     {
//         if (!DS18B20_ResetCheck(i))
//             continue;
//         DS18B20_WriteByte(i, 0xCC); // 跳过ROM操作
//         DS18B20_WriteByte(i, 0x44); // 启动温度转换
//     }
//     HAL_Delay(500); // 等待温度转换完成
//     for (uint8_t i = 0; i < (sizeof(handle) / sizeof(handle[0])); i++)
//     {
//         handle[i].Temp = 0;
//         if (!DS18B20_ResetCheck(i))
//             continue;
//         DS18B20_WriteByte(i, 0xCC); // 跳过ROM操作
//         DS18B20_WriteByte(i, 0xBE); // 读取温度寄存器
//         handle[i].Temp = DS18B20_ReadByte(i);
//         handle[i].Temp |= (DS18B20_ReadByte(i) << 8);
//     }
// }

#else

float DS18B20_ReadTempe(uint8_t object)
{

    if (!DS18B20_ResetCheck(object))
        return 0.0f;
    DS18B20_WriteByte(object, 0xCC); // 跳过ROM操作
    DS18B20_WriteByte(object, 0x44); // 启动温度转换

    HAL_Delay(500); // 等待温度转换完成

    if (!DS18B20_ResetCheck(object))
        return 0.0f;
    DS18B20_WriteByte(object, 0xCC); // 跳过ROM操作
    DS18B20_WriteByte(object, 0xBE); // 读取温度寄存器

    uint16_t temp;
    temp = DS18B20_ReadByte(object);
    temp |= (DS18B20_ReadByte(object) << 8);

    float temperature = (float)temp * 0.0625f;
    return temperature;
}

#endif
